/**
    ******************************************************************************
    * @file    main.c 
    * @author  18408107475@163.com
    * @version v1.0
    * @date    2025-04-08
    * @brief   STM32F103 USART通信示例
    * @details 
    * 功能特性：
    * - 实现USART1/2/3串口通信(波特率可配置)
    * - 支持数据接收中断和回显功能
    * - 提供多种数据发送方式(字节/数组/字符串/数字)
    * - 支持printf重定向
    * - LED和蜂鸣器控制反馈
    * 
    * 硬件连接：
    * - USART1_TX -> PA9
    * - USART1_RX -> PA10
    * - USART2_TX -> PA2
    * - USART2_RX -> PA3
    * - USART3_TX -> PB10
    * - USART3_RX -> PB11
    * - LED1 -> PB5 (低电平点亮)
    * - LED2 -> PE5 (低电平点亮)
    * - 蜂鸣器 -> PB8 (高电平触发)
    * - 按键 -> PE4 (下降沿触发)
    * 
    * 注意事项：
    * 1. 使用前需确保硬件连接正确
    * 2. 浮空输入引脚需外部上拉/下拉电阻
    * 3. 使用printf需在工程设置中启用MicroLIB
    * 4. 中断服务函数中应避免耗时操作
    ******************************************************************************
**/

/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f10x.h"  // STM32标准外设库
#include <stdio.h>      // 标准输入输出
#include <stdarg.h>     // 可变参数支持

/* 宏定义 --------------------------------------------------------------------*/
#define LED1_ON()  GPIO_ResetBits(GPIOB, GPIO_Pin_5)
#define LED1_OFF() GPIO_SetBits(GPIOB, GPIO_Pin_5)
#define LED2_ON()  GPIO_ResetBits(GPIOE, GPIO_Pin_5)
#define LED2_OFF() GPIO_SetBits(GPIOE, GPIO_Pin_5)
#define BEEP_ON()  GPIO_SetBits(GPIOB, GPIO_Pin_8)
#define BEEP_OFF() GPIO_ResetBits(GPIOB, GPIO_Pin_8)

#define __LED_STD_CONFIG_H

void LED_STD_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 开启GPIOB和GPIOE时钟（APB2总线） */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);

    /* 配置PB5为50MHz推挽输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;        // 选择引脚5
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  // 推挽输出模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 最高速度
    GPIO_Init(GPIOB, &GPIO_InitStructure);            // 应用配置

    /* 配置PE5为50MHz推挽输出（复用相同结构体） */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_Init(GPIOE, &GPIO_InitStructure);

    /* 设置初始状态 */
    GPIO_SetBits(GPIOB, GPIO_Pin_5);   // PB5高电平，LED1灭
    GPIO_SetBits(GPIOE, GPIO_Pin_5);   // PE5低高平，LED2灭
}

/* 函数声明 ------------------------------------------------------------------*/
void LED_Config(void);      // LED初始化
void BEEP_Config(void);     // 蜂鸣器初始化
void KEY_Config(void);      // 按键初始化
void Delay_us(uint32_t xus);// 微秒延时
void Delay_ms(uint32_t xms);// 毫秒延时
void Delay_s(uint32_t xs);  // 秒延时

void USART1_Config(u32 baud);   // USART1初始化
void USART2_Config(u32 baud);   // USART2初始化
void USART3_Config(u32 baud);   // USART3初始化

void USART1_IRQHandler(void);   // USART1中断服务函数
void USART2_IRQHandler(void);   // USART2中断服务函数
void USART3_IRQHandler(void);   // USART3中断服务函数

void USART_SendByte(USART_TypeDef* USARTx, u8 Byte);  // 发送单字节
void USART_SendArray(USART_TypeDef* USARTx, u8 *Array, u16 Length); // 发送数组
void USART_SendString(USART_TypeDef* USARTx, char *String);         // 发送字符串
void USART_SendNumber(USART_TypeDef* USARTx, u32 Num, u8 Length);   // 发送数字
void USART_Printf(USART_TypeDef* USARTx, char *format, ...);        // 格式化输出

/* 全局变量 ------------------------------------------------------------------*/
volatile u8 USART1_RxData = 0;  // USART1接收数据
volatile u8 USART2_RxData = 0;  // USART2接收数据
volatile u8 USART3_RxData = 0;  // USART3接收数据

/**
    ******************************************************************************
    * 函数名称：LED_Config
    * 功能描述：初始化LED控制引脚
    * 输入参数：无
    * 返回值  ：无
    ******************************************************************************
**/
void LED_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 开启GPIOB和GPIOE时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);

    /* 配置PB5为推挽输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* 配置PE5为推挽输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_Init(GPIOE, &GPIO_InitStructure);

    /* 初始状态：LED灭 */
    LED1_OFF();
    LED2_OFF();
}

/**
    ******************************************************************************
    * 函数名称：BEEP_Config
    * 功能描述：初始化蜂鸣器控制引脚
    * 输入参数：无
    * 返回值  ：无
    ******************************************************************************
**/
void BEEP_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 开启GPIOB时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    /* 配置PB8为推挽输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* 初始状态：蜂鸣器关闭 */
    BEEP_OFF();
}

/**
    ******************************************************************************
    * 函数名称：KEY_Config
    * 功能描述：初始化按键引脚和外部中断
    * 输入参数：无
    * 返回值  ：无
    ******************************************************************************
**/
void KEY_Config(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* 开启GPIOE时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);

    /* 配置PE4为浮空输入 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOE, &GPIO_InitStructure);

    /* 开启AFIO时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    /* 将PE4映射到EXTI4 */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);

    /* 配置EXTI4为下降沿触发 */
    EXTI_InitStructure.EXTI_Line = EXTI_Line4;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    /* 配置NVIC */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

/**
    ******************************************************************************
    * 函数名称：Delay_us
    * 功能描述：微秒级延时
    * 输入参数：xus - 延时时长(us)
    * 返回值  ：无
    ******************************************************************************
**/
void Delay_us(uint32_t xus)
{
    SysTick->LOAD = 72 * xus;       // 设置重装载值(72MHz主频)
    SysTick->VAL = 0x00;            // 清空计数器
    SysTick->CTRL = 0x00000005;     // 使用外部时钟
    while(!(SysTick->CTRL & 0x00010000)); // 等待计数完成
    SysTick->CTRL = 0x00000004;     // 关闭定时器
}

/**
    ******************************************************************************
    * 函数名称：Delay_ms
    * 功能描述：毫秒级延时
    * 输入参数：xms - 延时时长(ms)
    * 返回值  ：无
    ******************************************************************************
**/
void Delay_ms(uint32_t xms)
{
    while(xms--) {
        Delay_us(1000);
    }
}

/**
    ******************************************************************************
    * 函数名称：Delay_s
    * 功能描述：秒级延时
    * 输入参数：xs - 延时时长(s)
    * 返回值  ：无
    ******************************************************************************
**/
void Delay_s(uint32_t xs)
{
    while(xs--) {
        Delay_ms(1000);
    }
}

/**
    ******************************************************************************
    * 函数名称：USART1_Config
    * 功能描述：配置USART1串口
    * 输入参数：baud - 波特率
    * 返回值  ：无
    ******************************************************************************
**/
void USART1_Config(u32 baud)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* 开启时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    /* 配置PA9(TX)为复用推挽输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* 配置PA10(RX)为浮空输入 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* USART参数配置 */
    USART_InitStructure.USART_BaudRate = baud;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USART1, &USART_InitStructure);

    /* 配置USART1中断 */
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* 使能接收中断 */
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    /* 使能USART1 */
    USART_Cmd(USART1, ENABLE);
}

/**
    ******************************************************************************
    * 函数名称：USART2_Config
    * 功能描述：配置USART2串口
    * 输入参数：baud - 波特率
    * 返回值  ：无
    ******************************************************************************
**/
void USART2_Config(u32 baud)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* 开启时钟 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    /* 配置PA2(TX)为复用推挽输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* 配置PA3(RX)为浮空输入 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* USART参数配置 */
    USART_InitStructure.USART_BaudRate = baud;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USART2, &USART_InitStructure);

    /* 配置USART2中断 */
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* 使能接收中断 */
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);

    /* 使能USART2 */
    USART_Cmd(USART2, ENABLE);
}

/**
    ******************************************************************************
    * 函数名称：USART3_Config
    * 功能描述：配置USART3串口
    * 输入参数：baud - 波特率
    * 返回值  ：无
    ******************************************************************************
**/
void USART3_Config(u32 baud)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* 开启时钟 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    /* 配置PB10(TX)为复用推挽输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* 配置PB11(RX)为浮空输入 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* USART参数配置 */
    USART_InitStructure.USART_BaudRate = baud;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USART3, &USART_InitStructure);

    /* 配置USART3中断 */
    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* 使能接收中断 */
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);

    /* 使能USART3 */
    USART_Cmd(USART3, ENABLE);
}

/**
    ******************************************************************************
    * 函数名称：USART1_IRQHandler
    * 功能描述：USART1中断服务函数
    * 输入参数：无
    * 返回值  ：无
    ******************************************************************************
**/
void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        USART1_RxData = USART_ReceiveData(USART1);
        USART_SendData(USART1, USART1_RxData); // 回显数据
        
        /* 根据接收数据控制LED */
        if(USART1_RxData == '1') {
            LED1_ON();
        }
        else if(USART1_RxData == '0') {
            LED1_OFF();
        }
        
        /* 清除中断标志 */
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

/**
    ******************************************************************************
    * 函数名称：USART2_IRQHandler
    * 功能描述：USART2中断服务函数
    * 输入参数：无
    * 返回值  ：无
    ******************************************************************************
**/
void USART2_IRQHandler(void)
{
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    {
        USART2_RxData = USART_ReceiveData(USART2);
        USART_SendData(USART2, USART2_RxData); // 回显数据
        
        /* 根据接收数据控制蜂鸣器 */
        if(USART2_RxData == '1') {
            BEEP_ON();
            Delay_ms(100);
            BEEP_OFF();
        }
        
        /* 清除中断标志 */
        USART_ClearITPendingBit(USART2, USART_IT_RXNE);
    }
}

/**
    ******************************************************************************
    * 函数名称：USART3_IRQHandler
    * 功能描述：USART3中断服务函数
    * 输入参数：无
    * 返回值  ：无
    ******************************************************************************
**/
void USART3_IRQHandler(void)
{
    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
    {
        USART3_RxData = USART_ReceiveData(USART3);
        USART_SendData(USART3, USART3_RxData); // 回显数据
        
        /* 根据接收数据控制LED2 */
        if(USART3_RxData == '1') {
            LED2_ON();
        }
        else if(USART3_RxData == '0') {
            LED2_OFF();
        }
        
        /* 清除中断标志 */
        USART_ClearITPendingBit(USART3, USART_IT_RXNE);
    }
}

/**
    ******************************************************************************
    * 函数名称：USART_SendByte
    * 功能描述：发送单个字节
    * 输入参数：
    *   USARTx - USART外设
    *   Byte - 要发送的字节
    * 返回值  ：无
    ******************************************************************************
**/
void USART_SendByte(USART_TypeDef* USARTx, u8 Byte)
{
    USART_SendData(USARTx, Byte);
    while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}

/**
    ******************************************************************************
    * 函数名称：USART_SendArray
    * 功能描述：发送字节数组
    * 输入参数：
    *   USARTx - USART外设
    *   Array - 数组指针
    *   Length - 数组长度
    * 返回值  ：无
    ******************************************************************************
**/
void USART_SendArray(USART_TypeDef* USARTx, u8 *Array, u16 Length)
{
    u16 i;
    for(i = 0; i < Length; i++) {
        USART_SendByte(USARTx, Array[i]);
    }
}

/**
    ******************************************************************************
    * 函数名称：USART_SendString
    * 功能描述：发送字符串
    * 输入参数：
    *   USARTx - USART外设
    *   String - 字符串指针
    * 返回值  ：无
    ******************************************************************************
**/
void USART_SendString(USART_TypeDef* USARTx, char *String)
{
    u8 i;
    for(i = 0; String[i] != '\0'; i++) {
        USART_SendByte(USARTx, String[i]);
    }
}

/**
    ******************************************************************************
    * 函数名称：USART_SendNumber
    * 功能描述：发送数字
    * 输入参数：
    *   USARTx - USART外设
    *   Num - 要发送的数字
    *   Length - 数字位数
    * 返回值  ：无
    ******************************************************************************
**/
void USART_SendNumber(USART_TypeDef* USARTx, u32 Num, u8 Length)
{
    u8 i;
    u32 temp = 1;
    
    /* 计算10的(Length-1)次方 */
    for(i = 0; i < Length - 1; i++) {
        temp *= 10;
    }
    
    /* 从高位到低位依次发送 */
    for(i = 0; i < Length; i++) {
        USART_SendByte(USARTx, (Num / temp) % 10 + '0');
        temp /= 10;
    }
}

/**
    ******************************************************************************
    * 函数名称：USART_Printf
    * 功能描述：格式化输出
    * 输入参数：
    *   USARTx - USART外设
    *   format - 格式化字符串
    *   ... - 可变参数
    * 返回值  ：无
    ******************************************************************************
**/
void USART_Printf(USART_TypeDef* USARTx, char *format, ...)
{
    char String[100];
    va_list arg;
    
    va_start(arg, format);
    vsprintf(String, format, arg);
    va_end(arg);
    
    USART_SendString(USARTx, String);
}

/**
    ******************************************************************************
    * 函数名称：fputc
    * 功能描述：重定向printf到USART1
    * 输入参数：
    *   ch - 要输出的字符
    *   f - 文件指针
    * 返回值  ：输出的字符
    ******************************************************************************
**/
int fputc(int ch, FILE *f)
{
    USART_SendByte(USART1, ch);
    return ch;
}

/**
    ******************************************************************************
    * 函数名称：main
    * 功能描述：主函数
    * 输入参数：无
    * 返回值  ：int
    ******************************************************************************
**/
int main(void)
{
    /* 硬件初始化 */
    LED_Config();
    BEEP_Config();
    KEY_Config();
    
    /* 串口初始化 */
    USART1_Config(115200);  // USART1初始化115200波特率
    USART2_Config(115200);  // USART2初始化115200波特率
    USART3_Config(9600);    // USART3初始化9600波特率
    
    /* 发送欢迎信息 */
    USART_SendString(USART1, "USART1 Ready!\r\n");
    USART_SendString(USART2, "USART2 Ready!\r\n");
    USART_SendString(USART3, "USART3 Ready!\r\n");
    
    /* 主循环 */
    while(1)
    {
        /* 按键检测 */
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0) {
            Delay_ms(20);  // 消抖
            if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0) {
                /* 按键按下，发送提示信息 */
                USART_Printf(USART1, "Button Pressed!\r\n");
                BEEP_ON();
                Delay_ms(100);
                BEEP_OFF();
                
                /* 等待按键释放 */
                while(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0);
            }
        }
        
        /* 其他任务 */
        // ...
    }
}

/*************************************END OF FILE**************************************/